package com.alibaba.algo.apiimpl.feign;

import com.alibaba.algo.constants.Constants;
import com.alibaba.algo.cooperation.common.BaseResult;
import com.alibaba.algo.cooperation.common.PagerEntity;
import com.alibaba.algo.cooperation.feign.service.EmployeeFeignService;
import com.alibaba.algo.cooperation.feign.vo.enums.OrgTypeEnum;
import com.alibaba.algo.cooperation.feign.vo.req.FeignSelectEmployeeListByNameOrCodeRequestVO;
import com.alibaba.algo.cooperation.feign.vo.req.FeignSelectEmployeeListRequestVO;
import com.alibaba.algo.cooperation.feign.vo.req.FeignSelectOrgInfoByEmployeeCodeListVO;
import com.alibaba.algo.cooperation.feign.vo.res.FeignEmployeeOrgInfoListVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.SelectEmployeeListRequestVO;
import com.alibaba.algo.cooperation.usercomponent.vo.res.user.EmployeeOrgAndPositionResponseVO;
import com.alibaba.algo.cooperation.usercomponent.vo.res.user.EmployeeOrgResVO;
import com.alibaba.algo.cooperation.usercomponent.vo.res.user.EmployeePositionResVO;
import com.alibaba.algo.cooperation.usercomponent.vo.res.user.SelectEmployeeBaseAndOrgInfoResVO;
import com.alibaba.algo.core.base.CoreTools;
import com.alibaba.algo.core.base.Pager;
import com.alibaba.algo.dao.user.SysEmployeeMapper;
import com.alibaba.algo.domain.user.SysEmployeeDomain;
import com.alibaba.algo.domain.user.SysEmployeeOrgDomain;
import com.alibaba.algo.domain.user.SysEmployeePositionDomain;
import com.alibaba.algo.domain.user.SysOrgDomain;
import com.alibaba.algo.domain.user.SysUserEmployeeDomain;
import com.alibaba.algo.entity.user.SysEmployee;
import com.alibaba.algo.entity.user.SysOrg;
import com.alibaba.algo.utils.ThreadPoolUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author fan.tianpeng
 * @date 2021/6/2 11:35
 */
@RestController
@Slf4j
public class EmployeeFeignServiceImpl implements EmployeeFeignService {

    @Autowired
    private SysEmployeeDomain sysEmployeeDomain;

    @Resource
    private SysEmployeeMapper sysEmployeeMapper;

    @Autowired
    private SysEmployeeOrgDomain sysEmployeeOrgDomain;

    @Autowired
    private SysEmployeePositionDomain sysEmployeePositionDomain;

    @Autowired
    private SysUserEmployeeDomain sysUserEmployeeDomain;

    @Autowired
    private SysOrgDomain sysOrgDomain;

    /**
     * 通过员工标识列表查询对应的员工名称映射关系
     *
     * @param vo 员工标识列表
     * @return 员工映射关系
     */
    @Override
    public BaseResult<Map<Long, String>> qryEmployeeNameMap(List<Long> vo) {
        if (CollectionUtils.isEmpty(vo)) {
            return BaseResult.buildSuccess(Collections.emptyMap());
        }
        Map<Long, SysEmployee> sysEmployeeMap = sysEmployeeDomain.qryEmployeeMapByIdList(vo);
        Map<Long, String> collect = sysEmployeeMap.entrySet().stream()
                .filter(map -> StringUtils.isNotEmpty(map.getValue().getEmployeeName()))
                .collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().getEmployeeName(), (v1, v2) -> v2));
        return BaseResult.buildSuccess(collect);
    }

    @Override
    public PagerEntity selectPageByNameOrCode(FeignSelectEmployeeListByNameOrCodeRequestVO vo) {
        //空值特判
        if (StringUtils.isEmpty(vo.getEmployeeCodeOrEmployeeName())) {
            FeignSelectEmployeeListRequestVO emptyVO = new FeignSelectEmployeeListRequestVO();
            BeanUtils.copyProperties(vo, emptyVO);
            return this.selectPage(emptyVO);
        }

        int tmp_page_size = Integer.MAX_VALUE - 1;

        //Feign Api专用VO声明
        FeignSelectEmployeeListRequestVO name_vo = new FeignSelectEmployeeListRequestVO();
        name_vo.setEmployeeName(vo.getEmployeeCodeOrEmployeeName());
        name_vo.setPageSize(tmp_page_size);
        name_vo.setPageIndex(1);
        FeignSelectEmployeeListRequestVO code_vo = new FeignSelectEmployeeListRequestVO();
        code_vo.setEmployeeCode(vo.getEmployeeCodeOrEmployeeName());
        code_vo.setPageSize(tmp_page_size);
        code_vo.setPageIndex(1);

        //分别调分页查询接口，拼接两个列表，转set判重
        PagerEntity name_res = this.selectPage(name_vo);
        List name_employee_list = name_res.getDataList();
        PagerEntity code_res = this.selectPage(code_vo);
        List code_employee_list = code_res.getDataList();
        code_employee_list.addAll(name_employee_list);
        Set employee_set = new HashSet<>(code_employee_list);
        List<SelectEmployeeBaseAndOrgInfoResVO> employee_list = new ArrayList(employee_set);
        employee_list.removeIf(item -> item.getId() == null);

        //生成pager
        int total = employee_list.size();
        Pager pager = Pager.newInstance((long) total, vo.getPageIndex(), vo.getPageSize());
        int start_pos = pager.getPageSize() * (pager.getPageIndex() - 1);
        int end_pos = Math.min(start_pos + pager.getPageSize(), total);

        return new PagerEntity(total, pager.getTotalPages(), pager.getPageSize(), pager.getPageIndex(), employee_list.subList(start_pos, end_pos));
    }

    /**
     * 递归排序组织
     */
    private void sortOrgList(List<SysOrg> sysOrgList, List<String> orgNameList, Long parentId) {
        for (SysOrg sysOrg : sysOrgList) {
            if (sysOrg.getId().equals(sysOrg.getParentId())) {
                log.info("id和parentId相同，异常数据{}", JSON.toJSONString(sysOrg));
                continue;
            }
            if (parentId.equals(sysOrg.getParentId())) {
                orgNameList.add(sysOrg.getOrgName());
                sortOrgList(sysOrgList, orgNameList, sysOrg.getId());
                return;
            }
        }
    }

    /**
     * 根据工号清单查询员工的主部门层级链路
     *
     * @param employeeCodeList 工号清单
     * @return
     */
    @Override
    public BaseResult<Map<String, String>> selectOrgNameLinkByEmployeeCodes(List<String> employeeCodeList) {
        // 1、检查参数合法性
        if (ObjectUtils.isEmpty(employeeCodeList)) {
            return BaseResult.buildError("参数为空");
        }

        // 2、去除重复工号
        employeeCodeList = employeeCodeList.stream().distinct().collect(Collectors.toList());

        // 3、判断数量是否超过上限
        if (employeeCodeList.size() > Constants.BATCH_QUERY_COUNT) {
            return BaseResult.buildError(String.format("单次查询数量超过上限%s", Constants.BATCH_QUERY_COUNT));
        }

        Map<String, String> employeeCodeMap = new HashMap<>();
        // 4、根据员工编号批量查询主部门信息
        // TODO 查询全量数据 OK
        List<FeignEmployeeOrgInfoListVO> primaryOrgInfoList = sysEmployeeOrgDomain.selectPrimaryOrgInfoByEmployeeCodeListDefaultAll(null, employeeCodeList);
        //List<FeignEmployeeOrgInfoListVO> primaryOrgInfoList = sysEmployeeOrgDomain.selectPrimaryOrgInfoByEmployeeCodeList(employeeCodeList);

        // 5、根据主部门ID查询组织链路
        Map<String, FeignEmployeeOrgInfoListVO> primaryOrgInfoMap = new HashMap<>();
        if (!ObjectUtils.isEmpty(primaryOrgInfoList)) {
            for (FeignEmployeeOrgInfoListVO primaryOrgInfo : primaryOrgInfoList) {
                primaryOrgInfoMap.put(primaryOrgInfo.getEmployeeCode(), primaryOrgInfo);
            }
        }
        for (String employeeCode : employeeCodeList) {
            String orgNameLink = "";
            employeeCodeMap.put(employeeCode, orgNameLink);
            // 无主组织，返回为空
            if (!primaryOrgInfoMap.containsKey(employeeCode)) {
                continue;
            }
            // 有主组织，返回组织链
            Long primaryOrgId = primaryOrgInfoMap.get(employeeCode).getPrimaryDeptId();
            List<SysOrg> orgList = sysOrgDomain.selectOrgIdListRecursiveToRoot(primaryOrgId);
            if (ObjectUtils.isEmpty(orgList)) {
                continue;
            }
            // 基于上下层关系排序
            log.info("sort before:{}", JSONObject.toJSONString(orgList));
            //先按大小排一遍，提高sortOrgList排序效率
            orgList.sort(new Comparator<SysOrg>() {
                @Override
                public int compare(SysOrg o1, SysOrg o2) {
                    return o1.getId().intValue() - o2.getId().intValue();
                }
            });
            List<String> orgNameList = new ArrayList<>();
            sortOrgList(orgList, orgNameList, 0L);
            log.info("sort after:{}", JSONObject.toJSONString(orgNameList));
            if (ObjectUtils.isEmpty(orgNameList)) {
                continue;
            }
            orgNameLink = String.join(",", orgNameList);
            employeeCodeMap.put(employeeCode, orgNameLink);
        }
        return BaseResult.buildSuccess(employeeCodeMap);
    }

    @Override
    public BaseResult<List<FeignEmployeeOrgInfoListVO>> selectOrgInfoByEmployeeCodeList(FeignSelectOrgInfoByEmployeeCodeListVO paramVO) {
        // 0、参数合法性检查
        if (null == paramVO) {
            return BaseResult.buildError("参数对象不能为空");
        }
        /*
        if (CollectionUtils.isEmpty(paramVO.getEmployeeCodeList())) {
            return BaseResult.buildError("employeeCodeList不能为空");
        }
        if (paramVO.getEmployeeCodeList().size() > Constants.BATCH_QUERY_COUNT) {
            return BaseResult.buildError("employeeCodeList数量不能超过:" + Constants.BATCH_QUERY_COUNT);
        }
        */

        // 1.根据员工编号批量查询主部门信息
        // TODO 查询全量数据 OK
        List<FeignEmployeeOrgInfoListVO> feignEmployeeOrgInfoListVOList = sysEmployeeOrgDomain.selectPrimaryOrgInfoByEmployeeCodeListDefaultAll(paramVO.getIsDeleted(), paramVO.getEmployeeCodeList());
        //List<FeignEmployeeOrgInfoListVO> feignEmployeeOrgInfoListVOList = sysEmployeeOrgDomain.selectPrimaryOrgInfoByEmployeeCodeList(paramVO.getEmployeeCodeList());

        // 2.根据主部门id递归查询所属公司信息
        if (!ObjectUtils.isEmpty(feignEmployeeOrgInfoListVOList)) {
            for (FeignEmployeeOrgInfoListVO feignEmployeeOrgInfoListVO : feignEmployeeOrgInfoListVOList) {
                List<FeignEmployeeOrgInfoListVO.Company> companyList = new ArrayList<>();
                // 递归查询主部门所属公司
                recursionOrg(companyList, feignEmployeeOrgInfoListVO.getPrimaryDeptParentId(), null);
                feignEmployeeOrgInfoListVO.setCompanyList(companyList);
            }
        }
        return BaseResult.buildSuccess(feignEmployeeOrgInfoListVOList);
    }

    private void recursionOrg(List<FeignEmployeeOrgInfoListVO.Company> companyList, Long primaryDeptParentId, String isDeleted) {
        SysOrg sysOrg = sysOrgDomain.selectByOrgIdDefaultAll(primaryDeptParentId, isDeleted);
        if (ObjectUtils.isEmpty(sysOrg)) {
            return;
        }
        if (OrgTypeEnum.COMPANY.getCode().equals(sysOrg.getOrgType())) {
            FeignEmployeeOrgInfoListVO.Company company = new FeignEmployeeOrgInfoListVO.Company();
            company.setCompanyCode(sysOrg.getOrgCode());
            company.setCompanyName(sysOrg.getOrgName());
            companyList.add(company);
            Long parentId = sysOrg.getParentId();
            if (ObjectUtils.isEmpty(parentId) || -1 == parentId) {
                return;
            }
        }
        recursionOrg(companyList, sysOrg.getParentId(), isDeleted);
    }

    @Override
    public PagerEntity selectPage(FeignSelectEmployeeListRequestVO paramVO) {
        SelectEmployeeListRequestVO tmpVO = new SelectEmployeeListRequestVO();
        BeanUtils.copyProperties(paramVO, tmpVO);
        long total = sysEmployeeMapper.countWithinUserByCustomPara(tmpVO);
        Integer pageIndex = paramVO.getPageIndex();
        Integer pageSize = paramVO.getPageSize();
        Pager pager = Pager.newInstance(total, pageIndex, pageSize);
        LinkedHashMap<String, Object> sortMap = new LinkedHashMap<>();
        sortMap.put("gmtCreated", "DESC");
        sortMap.put("id", "DESC");
        List<SelectEmployeeBaseAndOrgInfoResVO> result = sysEmployeeMapper.pageWithinUserByCustomPara(tmpVO, pager.getStart(), pager.getEnd(), CoreTools.getSortStr(sortMap));
        ExecutorService threadPool = ThreadPoolUtil.getThreadPool();
        //多线程并发处理
        Collections.synchronizedList(result).parallelStream().forEach(item -> {
            FutureTask<List<EmployeeOrgAndPositionResponseVO>> orgAndPosts = new FutureTask<>(() -> sysEmployeeDomain.selectOrgAndPositionList(item.getId()));
            threadPool.submit(orgAndPosts);
            FutureTask<List<EmployeeOrgResVO>> orgs = new FutureTask<>(() -> sysEmployeeOrgDomain.selectEmployeeOrgListByEmployeeId(item.getId()));
            threadPool.submit(orgs);
            FutureTask<List<EmployeePositionResVO>> posts = new FutureTask<>(() -> sysEmployeePositionDomain.selectEmployeePositionListByEmployeeId(item.getId()));
            threadPool.submit(posts);
            try {
                item.setOrgAndPositionList(orgAndPosts.get());
                item.setOrgList(orgs.get());
                item.setPositionList(posts.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!ObjectUtils.isEmpty(item.getId())) {
                log.info("EmployeeFeignService selectPage() result:employeeId:{}", item.getId());
                Long userId = sysUserEmployeeDomain.selectUserIdByEmployeeId(item.getId());
                log.info("EmployeeFeignService selectPage() result:userId:{}", userId);
                item.setUserId(userId);
            }
        });
        return new PagerEntity(total, pager.getTotalPages(), pager.getPageSize(), pager.getPageIndex(), result);
    }

    @Override
    public BaseResult<Map<String, String>> qryEmployeeNameMapByCodes(List<String> empCodeList) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(empCodeList)) {
            return BaseResult.buildSuccess(Collections.emptyMap());
        }
        Map<String, SysEmployee> sysEmployeeMap = sysEmployeeDomain.qryEmployeeNameMapByCodes(empCodeList);
        Map<String, String> collect = sysEmployeeMap.entrySet().stream()
                .filter(map -> StringUtils.isNotEmpty(map.getValue().getEmployeeName()))
                .collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().getEmployeeName(), (v1, v2) -> v2));
        return BaseResult.buildSuccess(collect);
    }
}
